package com.ruoyi.service.impl;

import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.mapper.HotelMapper;
import com.ruoyi.mapper.HouseMapper;
import com.ruoyi.mapper.OrderMapper;
import com.ruoyi.mapper.RPMapper;
import com.ruoyi.service.GroundService;
import com.ruoyi.service.LogService;
import com.ruoyi.service.OrderService;
import com.ruoyi.service.RPService;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.io.ByteArrayInputStream;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.*;

@Service
public class OrderServiceImpl implements OrderService {

    private static Logger hotelSuccess = LoggerFactory.getLogger("hotel_success");

    @Value("${eLong.username}")
    private String username;

    @Value("${eLong.password}")
    private String password;

    @Autowired
    HotelMapper hotelMapper;

    @Autowired
    RPMapper rpMapper;

    @Autowired
    OrderMapper orderMapper;

    @Autowired
    HouseMapper houseMapper;

    @Autowired
    RPService rpService;

    @Autowired
    GroundService groundService;

    @Autowired
    LogService logService;

    // 订单顺序
    // 定时任务全增量更新房态、全增量更新价格、全增量更新库存、全增量更新产品预定规则
    // 下单→是否可订→创建订单→轮询订单结果→推送供应商订单号→

    @Override
    public String isOrder(String ru) throws Exception {
        String convertedString = ru.replace("\\\"", "\"");
        SAXReader reader = new SAXReader();
        ByteArrayInputStream inputStream = new ByteArrayInputStream(convertedString.getBytes(StandardCharsets.UTF_8));
        Document document = reader.read(inputStream);
        Element rootElement = document.getRootElement();

        // 根元素
        // 可订检查:OTA_InventoryCheckRQ
        // 创建订单:OTA_HotelResRQ
        // 取消订单:OTA_CancelRQ
        // 变更订单:OTA_ModifyResRQ
        // 轮询订单状态:OTA_GetRerStatusRQ
        String rootName = rootElement.getName();

        if ("OTA_InventoryCheckRQ".equals(rootName)) {
            hotelSuccess.info("可订检查");
            hotelSuccess.info("可订检查原始报文：");
            hotelSuccess.info(ru);
            return OTA_InventoryCheckRQ(rootElement);
        } else if ("OTA_HotelResRQ".equals(rootName)) {
            hotelSuccess.info("创建订单");
            hotelSuccess.info("创建订单原始报文：");
            hotelSuccess.info(ru);
            return OTA_HotelResRQ(rootElement);
        } else if ("OTA_GetRerStatusRQ".equals(rootName)) {
            hotelSuccess.info("轮询");
            hotelSuccess.info("轮询原始报文：");
            hotelSuccess.info(ru);
            return OTA_GetRerStatusRQ(rootElement);
        } else if ("OTA_CancelRQ".equals(rootName)) {
            hotelSuccess.info("取消订单");
            hotelSuccess.info("取消订单原始报文：");
            hotelSuccess.info(ru);
            return OTA_CancelRQ(rootElement);
        }
        return "";
    }

    /**
     * 可订检查
     *
     * @param rootElement
     * @return
     */
    public String OTA_InventoryCheckRQ(Element rootElement) {
        // 可订检查主要传过来 HotelCode,RoomTypeCode,RatePlanCode维度指向RP
        // (1) 年龄类型数组,7=婴儿，8=儿童，10=成人 GuestCount,人数Count
        // (2) 请求的房数 RoomCount
        // (3) 到店日期,离店日期 TimeSpan-Start-End

        // 可订检查主要返回 EchoToken,TimeStamp,RoomTypeCode,RatePlanCode
        // (1) 是否支持30分钟免费取消 <FreeCancelable FreeCancelableVal="true"/>
        // (2) 价格信息 Prices-Price-Base,Price是数组,主要存放
        // 日期EffectDate(到店日期到离店日期前一天),卖价SalePrice,底价BasePrice,剩余房量Allotment,
        // 直连超售库存类型房量DcOverSaleAllotment(非保留房必须对接),
        // 直连添加库存类型房量DcAddAllotment(保留房无库存返回0)
        // 直连签约库存类型房量DcContractAllotment(-1)
        // 直连买断库存类型房量DcBuyOutAllotment(-1)

        // 失败价格,房量都返回0
        // 必要参数,可订检查主要取到店日期和离店日期
        String EchoToken = rootElement.attributeValue("EchoToken");
        Element hotelReservations = rootElement.element("HotelReservations");
        Element hotelReservation = hotelReservations.element("HotelReservation");
        Element roomStay = hotelReservation.element("RoomStay");
        String HotelId = roomStay.element("BasicPropertyInfo").attributeValue("HotelCode");
        String HouseId = roomStay.element("RoomTypes").element("RoomType").attributeValue("RoomTypeCode");
        String RPID = roomStay.element("RatePlans").element("RatePlan").attributeValue("RatePlanCode");
        Element timeSpan = hotelReservation.element("ResGlobalInfo").element("TimeSpan");
        String start = timeSpan.attributeValue("Start");
        String end = timeSpan.attributeValue("End");

        // 取出酒店信息
        Map hotelObj = hotelMapper.getHotelObjByHotelId(HotelId);

        // 是否30分钟免费取消
        String isFreeCancelable = hotelObj.get("isFreeCancelable").toString();

        // 时间戳
        String TimeStamp = System.currentTimeMillis() + "";

        // 构造xml
        Document document = DocumentHelper.createDocument();
        Element otaInventoryCheckRS = document.addElement("OTA_InventoryCheckRS");
        otaInventoryCheckRS.addAttribute("TimeStamp", TimeStamp);
        otaInventoryCheckRS.addAttribute("Version", "1.000");
        otaInventoryCheckRS.addAttribute("EchoToken", EchoToken);

        Element hotelResult = otaInventoryCheckRS.addElement("HotelResult");
        hotelResult.addElement("HotelID").setText(HotelId);

        Element hotelProducts = hotelResult.addElement("HotelProducts");
        Element hotelProduct = hotelProducts.addElement("HotelProduct");
        // 是否30分钟免费取消
        if ("1".equals(isFreeCancelable)) {
            hotelProduct.addElement("FreeCancelable").addAttribute("FreeCancelableVal", "true");
        }

        Element roomTypes = hotelProduct.addElement("RoomTypes");
        roomTypes.addElement("RoomType").addAttribute("RoomTypeCode", HouseId);

        Element ratePlans = hotelProduct.addElement("RatePlans");
        ratePlans.addElement("RatePlan").addAttribute("RatePlanCode", RPID);

        Element prices = hotelProduct.addElement("Prices");
        List<String> datesInRange = DateUtils.getDatesInRange(start, end);
        for (int i = 0; i < datesInRange.size() - 1; i++) {
            // 这里循环price
            String day = datesInRange.get(i);
            Map map = new HashMap();
            map.put("rpId", RPID);
            map.put("houseDay", day);

            Map obj = orderMapper.getHouseObjAndRpObj(map);

            Object ePrice = obj.get("ePrice");
            Object nQuantityNum = obj.get("nQuantityNum");
            Object yQuantityNum = obj.get("yQuantityNum");
            if (yQuantityNum == null) {
                yQuantityNum = 0;
            }
            Object houseStatus = obj.get("houseStatus");
            Object rpStatus = obj.get("rpStatus");

            if (houseStatus == null || "0".equals(houseStatus.toString())) {
                // 通过房态关闭
                nQuantityNum = "0";
            }

            if (rpStatus == null || "0".equals(houseStatus.toString())) {
                // 通过价格无效时间关闭
                nQuantityNum = 0;
            }

            Element price = prices.addElement("Price");
            Element base = price.addElement("Base");
            base.addAttribute("EffectDate", day);
            base.addAttribute("SalePrice", ePrice.toString());
            base.addAttribute("BasePrice", ePrice.toString());
            base.addAttribute("Allotment", (Integer.parseInt(nQuantityNum.toString()) + Integer.parseInt(yQuantityNum.toString())) + "");
            base.addAttribute("DcOverSaleAllotment", nQuantityNum + "");
            base.addAttribute("DcAddAllotment", yQuantityNum + "");
            base.addAttribute("DcContractAllotment", "-1");
            base.addAttribute("DcBuyOutAllotment", "-1");
        }
        String resXML = document.asXML();
        hotelSuccess.info("可订检查响应报文");
        hotelSuccess.info(resXML);
        return resXML;
    }

    public String OTA_HotelResRQ(Element rootElement) {
        // 创建订单主要传过来:
        // (1) 30分钟免费取消标识。非必传，只有订单中的酒店支持30分钟免费取消，订单才会传该节点 FreeCancelable
        // (2) 艺龙订单号 UniqueID
        // (3) 住店信息,是一个数组,数组元素包括(住店日期EffectDate、落地卖价SaleAmountOriginal) Rates-Rate-Base
        // (4) 住店合计信息,合计卖价 Rates-Rate-Base-Total
        // (5) 入住人员类型信息,年龄类型AgeQualifyingCode 7=婴儿，8=儿童，10=成人,人数Count,GuestCounts-GuestCount
        // (6) 客人信息,姓名Surname,英文名MiddleName,ResGuests-ResGuest-Profiles-ProfileInfo-Profile-Customer-PersonName-RoomGuest
        // (7) 房间数量RoomNum,入离时间TimeSpan Start入,end离,到店最早时间EarliestCheckInTime,到店最晚时间LatestCheckInTime,备注Remark
        // Guarantee担保信息,都在ResGlobalInfo里
        // (8) 订单是否可以取消CanBeCanceled,提前几天可以取消CancelBeforeDays,提前几点可以取消CancelBeforeTime,罚金类别CashScaleType
        // 都在RatePlanPolicy里
        // (9) 是否轮询ElongInventoryType,轮询=OnRequest,即使确认=Confirm

        // 创建订单可以校验的有:
        // 2000 无法解析参数(判断xml是否合法)
        // 3202	酒店编码不存在或者无效
        // 3203 房型ID不存在
        // 3204 RPID不存在
        // 3205 客人姓名为空
        // 3206 住店日期为空
        // 3207 离店日期为空
        // 3208 客人人数为空
        // 3210 价格错误
        // 3211 房量不足

        // 创建订单主要返回TimeStamp,EchoToken,艺龙ID订单号,供应商订单号
        // 失败返回失败编码

        System.out.println("创建订单");

        // 校验
        boolean isVerification = true;
        int errorCode = 0;
        String errorStr = "";

        String UserName = rootElement.attributeValue("UserName");
        String Password = rootElement.attributeValue("Password");

        if (!UserName.equals(username) || !Password.equals(password)) {
            isVerification = false;
            errorCode = 7000;
            errorStr = "用户名密码错误";
        }

        // 必要参数
        String EchoToken = rootElement.attributeValue("EchoToken");
        String createReqTime = rootElement.attributeValue("TimeStamp");
        String TimeStamp = System.currentTimeMillis() + "";

        // RequestorID
        String RequestorID = rootElement.element("POS").element("Source").element("RequestorID").attributeValue("ID");

        // OnRequest表示非即时确认(需要轮询)；Confirm表示即时确认
        String ElongInventoryType = rootElement.element("ElongInventoryType").getText();

        // 是否可以取消
        Element RatePlanPolicyElement = rootElement.element("RatePlanPolicy");
        String canBeCanceled = RatePlanPolicyElement.element("CanBeCanceled").getText();

        if (isVerification == true) {
            Element hotelReservations = rootElement.element("HotelReservations");
            Element hotelReservation = hotelReservations.element("HotelReservation");
            // 艺龙订单号
            String ElongOrderId = hotelReservation.element("UniqueID").attributeValue("ID");

            // 这里需要幂等去重
            Map orderObj = orderMapper.getOrderByeOrderCode(ElongOrderId);
            if (orderObj != null) {
                // 重复了,返回已存在的订单编号
                String resXML = HotelResRQSuccessXml(EchoToken, TimeStamp, RequestorID, ElongOrderId, orderObj.get("orderCode").toString());
                return resXML;
            }

            // 是否30分钟免费取消
            Element FreeCancelableElement = hotelReservation.element("FreeCancelable");
            // 房间数
            Element resGlobalInfo = hotelReservation.element("ResGlobalInfo");
            String roomNum = resGlobalInfo.element("RoomNum").getText();
            //到店时间
            Element TimeSpan = resGlobalInfo.element("TimeSpan");
            String start = TimeSpan.attributeValue("Start");
            String end = TimeSpan.attributeValue("End");
            // 人数、房型ID、RPID
            Element RoomStays = hotelReservation.element("RoomStays");
            Element RoomStay = RoomStays.element("RoomStay");
            String count = RoomStay.element("GuestCounts").element("GuestCount").attributeValue("Count");
            String RoomTypeCode = RoomStay.element("RoomTypes").element("RoomType").attributeValue("RoomTypeCode");
            String RatePlanCode = RoomStay.element("RatePlans").element("RatePlan").attributeValue("RatePlanCode");
            // 酒店ID
            String HotelCode = RoomStay.element("BasicPropertyInfo").attributeValue("HotelCode");
            // 合计原始落地的底价、卖价
            Element RoomRates = RoomStay.element("RoomRates");
            Element RoomRate = RoomRates.element("RoomRate");
            Element Rates = RoomRate.element("Rates");
            Element Rate = Rates.element("Rate");
            Element Total = Rate.element("Total");
            String BaseAmountOriginal = Total.attributeValue("BaseAmountOriginal");
            String SaleAmountOriginal = Total.attributeValue("SaleAmountOriginal");
            // 入住人姓名集合
            String names = "";
            Element ResGuests = hotelReservation.element("ResGuests");
            Element ResGuest = ResGuests.element("ResGuest");
            Element Profiles = ResGuest.element("Profiles");
            Element ProfileInfo = Profiles.element("ProfileInfo");
            Element Profile = ProfileInfo.element("Profile");
            Element Customer = Profile.element("Customer");

            List<Element> PersonName = Customer.elements("PersonName");
            for (Element ele : PersonName) {
                List<Element> RoomGuests = ele.elements("RoomGuest");
                for (Element roomGuest : RoomGuests) {
                    String name = roomGuest.element("Surname").getText();
                    names += name + ",";
                }
            }
            names = names.substring(0, names.length() - 1);

            // 要生成供应商订单号
            String orderCode = getOrderCode();
            Map map = new HashMap();
            map.put("orderCode", orderCode);
            map.put("createReqTime", createReqTime);
            map.put("orderType", ElongInventoryType);
            map.put("eOrderCode", ElongOrderId);
            map.put("fjsNum", roomNum);
            map.put("rsNum", count);
            map.put("names", names);
            map.put("start", start);
            map.put("end", end);
            map.put("BaseAmountOriginal", BaseAmountOriginal);
            map.put("SaleAmountOriginal", SaleAmountOriginal);
            map.put("hotelId", HotelCode);
            map.put("houseId", RoomTypeCode);
            map.put("RatePlanCode", RatePlanCode);
            if (ElongInventoryType.indexOf("Confirm") != -1) {
                // 保留房为及时确认
                map.put("orderStatus", 1);
            } else {
                map.put("orderStatus", 0);
            }
            if (FreeCancelableElement != null) {
                map.put("isCancelable", FreeCancelableElement.attributeValue("Cancelable"));
            } else {
                map.put("isCancelable", "false");
            }
            map.put("canBeCanceled", canBeCanceled);

            // 获取采购价
            List<Map> rpPriceData = rpMapper.getRpPriceByRpIdAndTime(RatePlanCode, start, end);
            // 插入完成后计算总采购价
            BigDecimal cgjOriginal = new BigDecimal(0);
            for (Map rpPriceDatum : rpPriceData) {
                BigDecimal rpPrice = new BigDecimal(rpPriceDatum.get("rpPrice").toString());
                cgjOriginal = cgjOriginal.add(rpPrice);
            }
            cgjOriginal = cgjOriginal.multiply(new BigDecimal(roomNum));
            map.put("cgjOriginal", cgjOriginal);
            // 插入到数据库
            int i = orderMapper.insertOrder(map);
            String orderId = map.get("orderId").toString();
            // 插入采购价
            orderMapper.insertOrderPrice(orderId, orderCode, rpPriceData);

            // 插入语音提醒
            insertRemind(orderCode, 0);

            // WebSocket提示
            /*
            Map hotelObj = hotelMapper.getHotelObjByHotelId(HotelCode);
            hotelObj.put("orderType",0);
            WebSocketUsers.sendMessageToUsersByText(JSONObject.toJSONString(hotelObj));
            */

            // 插入来单日志
            if (ElongInventoryType.indexOf("Confirm") != -1) {
                logService.insertOrderLog(orderCode, "平台来单-保留房(新订)", 1);
                logService.insertOrderLog(orderCode, "平台自动接单-保留房", 1);
            } else {
                logService.insertOrderLog(orderCode, "平台来单-非保留房(新订)", 1);
            }
            if (i > 0) {
                // 插入数据库后,要修改保留房数量,先拿到房间数量(roomNum)
                // 判断ElongInventoryType是不是Confirm来区分是不是保留房订单
                if (ElongInventoryType.indexOf("Confirm") != -1) {
                    List<String> datesInRange = DateUtils.getDatesInRange(start, end);
                    for (int j = 0; j < datesInRange.size() - 1; j++) {
                        String day = datesInRange.get(j);
                        Map map1 = new HashMap();
                        map1.put("rpId", RatePlanCode);
                        map1.put("houseDay", day);
                        Map houseObjAndRpObj = orderMapper.getHouseObjAndRpObj(map1);

                        Map map2 = new HashMap();
                        map2.put("houseId", RoomTypeCode);
                        map2.put("startTime", day);
                        map2.put("endTime", day);
                        int yQuantityNum = Integer.parseInt(houseObjAndRpObj.get("yQuantityNum").toString()) - Integer.parseInt(roomNum);
                        map2.put("yQuantityNum", yQuantityNum + "");

                        // 扣减为完为0,取消保留房
                        if (yQuantityNum <= 0) {
                            List<String> roomTypeCode = new ArrayList<>();
                            roomTypeCode.add(RoomTypeCode);
                            JSONObject jsonObject = groundService.updateRoomTypeAmount(HotelCode, 0, day, day, 1, roomTypeCode, "CLOSE");
                            if (jsonObject.getInteger("retcode") == 0) {
                                houseMapper.updateHouseDayData(map2);
                            }
                        } else {
                            houseMapper.updateHouseDayData(map2);
                        }
                    }
                }
                String resXML = HotelResRQSuccessXml(EchoToken, TimeStamp, RequestorID, ElongOrderId, orderCode);
                return resXML;
            }
        } else {
            Document document = DocumentHelper.createDocument();
            Element otaInventoryCheckRS = document.addElement("OTA_HotelResRS");
            otaInventoryCheckRS.addAttribute("TimeStamp", TimeStamp);
            otaInventoryCheckRS.addAttribute("Version", "1.000");
            otaInventoryCheckRS.addAttribute("EchoToken", EchoToken);

            Element pos = otaInventoryCheckRS.addElement("POS");
            Element source = pos.addElement("Source");
            Element requestorID = source.addElement("RequestorID");
            requestorID.addAttribute("ID", RequestorID);
            requestorID.addAttribute("Type", "2");

            Element Errors = otaInventoryCheckRS.addElement("Errors");
            Errors.addElement("Error").addAttribute("Language", "en-us").addAttribute("Type", "3").addAttribute("Code", errorCode + "").setText(errorStr);

            Element UniqueID = otaInventoryCheckRS.addElement("UniqueID").addAttribute("Type", "10").addAttribute("ID", "0");
            UniqueID.addElement("CompanyName").setText("ahyy");
            String resXML = document.asXML();
            hotelSuccess.info("创建订单响应报文");
            hotelSuccess.info(resXML);
            return resXML;
        }
        return "";
    }

    /**
     * 轮询检查
     *
     * @return
     */
    public String OTA_GetRerStatusRQ(Element rootElement) {
        // 轮询检查主要传过来:EchoToken,艺龙订单号和供应商订单号

        // 轮询检查主要返回EchoToken,TimeStamp,艺龙订单号和供应商订单号,
        // (1) 订单状态 OrderStatus   OK:确认,NO:不确认,Pending:等待,Cancel:订单已取消

        // 轮询返回失败,确认号无效
        System.out.println("轮询检查");

        // 供应商订单号
        String EchoToken = rootElement.attributeValue("EchoToken");
        List<Element> uniqueID = rootElement.elements("UniqueID");
        // 艺龙订单号
        String ElongOrderId = uniqueID.get(0).attributeValue("ID");
        // 供应商订单号
        String orderCode = uniqueID.get(1).attributeValue("ID");
        // 取订单数据
        Map orderObj = orderMapper.getOrderByOrderCode(orderCode);
        String TimeStamp = System.currentTimeMillis() + "";
        if (orderObj != null) {
            String orderStatus = orderObj.get("orderStatus").toString();
            Document document = DocumentHelper.createDocument();
            Element otaInventoryCheckRS = document.addElement("OTA_HotelResRS");
            otaInventoryCheckRS.addAttribute("TimeStamp", TimeStamp);
            otaInventoryCheckRS.addAttribute("Version", "1.000");
            otaInventoryCheckRS.addAttribute("EchoToken", EchoToken);

            Element UniqueID1 = otaInventoryCheckRS.addElement("UniqueID").addAttribute("Type", "14").addAttribute("ID", ElongOrderId);
            UniqueID1.addElement("CompanyName").setText("Elong");

            Element UniqueID2 = otaInventoryCheckRS.addElement("UniqueID").addAttribute("Type", "10").addAttribute("ID", orderCode);
            UniqueID2.addElement("CompanyName").setText("ahyy");

            Element OrderStatus = otaInventoryCheckRS.addElement("OrderStatus");
            if ("0".equals(orderStatus)) {
                OrderStatus.setText("Pending");
            } else if ("1".equals(orderStatus)) {
                OrderStatus.setText("OK");
            } else if ("2".equals(orderStatus)) {
                OrderStatus.setText("NO");
            } else if ("3".equals(orderStatus)) {
                OrderStatus.setText("Cancel");
            }
            String resXML = document.asXML();
            hotelSuccess.info("轮询检查响应报文");
            hotelSuccess.info(resXML);
            return resXML;
        } else {
            Document document = DocumentHelper.createDocument();
            Element otaInventoryCheckRS = document.addElement("OTA_HotelResRS");
            otaInventoryCheckRS.addAttribute("TimeStamp", TimeStamp);
            otaInventoryCheckRS.addAttribute("Version", "1.000");
            otaInventoryCheckRS.addAttribute("EchoToken", EchoToken);

            Element errors = otaInventoryCheckRS.addElement("Errors");
            errors.addElement("Error").addAttribute("Language", "en-us").addAttribute("Type", "3").addAttribute("Code", "450").setText("Unable to cancel the reservation: the hotel confirmation number is invalid");
            String resXML = document.asXML();
            hotelSuccess.info("轮询检查响应报文");
            hotelSuccess.info(resXML);
            return resXML;
        }
    }

    /**
     * 取消订单
     *
     * @return
     */
    public String OTA_CancelRQ(Element rootElement) {
        // 取消订单主要传过来:EchoToken,艺龙订单号和供应商订单号
        String TimeStamp = System.currentTimeMillis() + "";
        String EchoToken = rootElement.attributeValue("EchoToken");
        String cancelReqTime = rootElement.attributeValue("TimeStamp");
        List<Element> uniqueID = rootElement.elements("UniqueID");
        // 艺龙订单号
        String ElongOrderId = uniqueID.get(0).attributeValue("ID");
        // 供应商订单号
        String orderCode = uniqueID.get(1).attributeValue("ID");
        // 订单数据
        Map orderObj = orderMapper.getOrderByOrderCode(orderCode);
        String hotelId = orderObj.get("hotelId").toString();
        // 酒店数据
        // Map hotelObj = hotelMapper.getHotelObjByHotelId(hotelId);
        // 取消订单,用于校验
        int orderCancelCount = orderMapper.getOrderCancelCountByOrderId(orderObj.get("orderId").toString());

        // 订单在第一次取消请求进来返回取消成功,会把订单状态改为已取消,这时候如果有轮询进来会返回订单已取消
        // 艺龙收到订单已取消后可能会再发起一次取消请求
        // 解决方案一：此处过滤重复取消订单,通过查询原始订单看看是否已经取消以及有了一条取消请求来验证是否重复
        // 解决方案二：优化SQL,取时间最先一条的取消订单
        String orderStatus = orderObj.get("orderStatus").toString();
        int errorCode = 0;
        String errorStr = "";

        // 生成取消订单
        Map map = new HashMap();
        String orderCancelCode = getOrderCode();
        map.put("orderCancelCode", orderCancelCode);
        map.put("cancelReqTime", cancelReqTime);
        map.put("orderId", orderObj.get("orderId"));

        if ("3".equals(orderStatus) && orderCancelCount > 0) {
            // 以防万一,先插入到重复表中
            orderMapper.insertCancelOrderRepeat(map);

            errorCode = 3200;
            errorStr = "订单已经取消";
            logService.insertOrderLog(orderCode, "订单收到重复取消请求,自动过滤(取消)", 1);
            String resXML = orderCancelFailXml(EchoToken, TimeStamp, errorCode, errorStr);
            return resXML;
        }
        // 插入数据库
        orderMapper.insertCancelOrder(map);
        // 插入语音提醒
        insertRemind(orderCancelCode, 1);

        // WebSocket提示
        /*
        Map hotelObj = hotelMapper.getHotelObjByHotelId(hotelId);
        hotelObj.put("orderType",1);
        WebSocketUsers.sendMessageToUsersByText(JSONObject.toJSONString(hotelObj));
         */

        // 插入来单日志
        logService.insertOrderLog(orderCode, "平台来单(取消)", 1);
        // 校验
        boolean isVerification = true;

        String UserName = rootElement.attributeValue("UserName");
        String Password = rootElement.attributeValue("Password");

        if (!UserName.equals(username) || !Password.equals(password)) {
            // 判断用户名密码
            isVerification = false;
            errorCode = 7000;
            errorStr = "用户名密码错误";
        } else {
            // 先看下是否处理
            if ("0".equals(orderStatus)) {
                // 没有处理允许取消
                isVerification = true;
                logService.insertOrderLog(orderCode, "自动同意取消,未处理订单(取消)", 1);
            } else if ("3".equals(orderStatus)) {
                errorCode = 3200;
                errorStr = "订单已经取消";
                isVerification = false;
                logService.insertOrderLog(orderCode, "该订单已经取消(取消)", 1);
            } else {
                // 管你是不是允许取消或者30分钟,先看是不是在同一天取消
                String startTime = orderObj.get("startTime").toString().replaceAll("T", " ") + ":00";
                boolean onTheSameDay = DateUtils.isOnTheSameDay(cancelReqTime, startTime);
                if (onTheSameDay == true) {
                    // 同一天不允许取消,前端设置订单状态,之后会同程会调用轮询
                    isVerification = false;
                    errorCode = 8000;
                    errorStr = "不满足取消规则";
                    logService.insertOrderLog(orderCode, "自动拒绝取消,同一天不允许取消", 1);
                } else {
                    // 先看下是否允许取消
                    if ("false".equals(orderObj.get("canBeCanceled").toString())) {
                        // 如果不允许取消,那就看下是否30分钟免费取消
                        if ("true".equals(orderObj.get("isCancelable").toString())) {
                            // 开启30分钟免费取消,判断是否大于30分钟
                            // 下单时间
                            String createReqTime = orderObj.get("createReqTime").toString().replaceAll("T", " ");

                            // 判断间隔
                            long l = DateUtils.calculateMinutesDifference(createReqTime, cancelReqTime);
                            if (l <= 30) {
                                // 小于三十分钟允许取消
                                isVerification = true;
                                logService.insertOrderLog(orderCode, "自动同意取消,满足30分钟免费取消", 1);
                            } else {
                                // 超过三十分钟直接失败
                                errorCode = 8000;
                                errorStr = "不满足取消规则";
                                isVerification = false;
                                logService.insertOrderLog(orderCode, "自动拒绝取消,酒店不允许取消且超过30分钟免费取消", 1);
                            }
                        } else {
                            // 没开启30分钟免费取消,取消失败
                            errorCode = 8000;
                            errorStr = "不满足取消规则";
                            isVerification = false;
                            logService.insertOrderLog(orderCode, "自动拒绝取消,酒店不允许取消且没开启30分钟免费取消", 1);
                        }
                    } else {
                        isVerification = true;
                        logService.insertOrderLog(orderCode, "自动同意取消", 1);
                    }
                }
            }
        }

        if (isVerification == true) {
            if (orderObj.get("orderType").toString().indexOf("Confirm") != -1) {
                // 判断是不是保留房,如果是保留房取消需要释放保留房数量
                String startTime = orderObj.get("startTime").toString().substring(0, 10);
                String endTime = orderObj.get("endTime").toString().substring(0, 10);
                List<String> datesInRange = DateUtils.getDatesInRange(startTime, endTime);
                String houseId = orderObj.get("houseId").toString();
                for (int j = 0; j < datesInRange.size() - 1; j++) {
                    String day = datesInRange.get(j);
                    Map map1 = new HashMap();
                    map1.put("houseId", houseId);
                    map1.put("startTime", day);
                    map1.put("endTime", day);
                    Map houseDayObj = houseMapper.getHouseDayList(map1).get(0);
                    int yQuantityNum = Integer.parseInt(houseDayObj.get("yQuantityNum").toString());
                    int fjsNum = Integer.parseInt(orderObj.get("fjsNum").toString());
                    Map map2 = new HashMap();
                    map2.put("yQuantityNum", yQuantityNum + fjsNum);
                    map2.put("houseId", houseId);
                    map2.put("startTime", day);
                    map2.put("endTime", day);
                    houseMapper.updateHouseDayData(map2);
                }
            }

            // 取消成功将订单状态修改为3(3=已取消)
            Map map1 = new HashMap();
            map1.put("orderId", orderObj.get("orderId").toString());
            map1.put("orderStatus", 3);
            orderMapper.updateOrder(map1);

            Document document = DocumentHelper.createDocument();
            Element otaCancelRS = document.addElement("OTA_CancelRS");
            otaCancelRS.addAttribute("EchoToken", EchoToken);
            otaCancelRS.addAttribute("TimeStamp", TimeStamp);
            otaCancelRS.addAttribute("Version", "1.000");
            otaCancelRS.addAttribute("Status", "Cancelled");
            otaCancelRS.addElement("Success").setText("success");
            otaCancelRS.addElement("UniqueID").addAttribute("Type", "14").addAttribute("ID", ElongOrderId).addElement("CompanyName").setText("Elong");
            otaCancelRS.addElement("UniqueID").addAttribute("Type", "10").addAttribute("ID", orderCode).addElement("CompanyName").setText("ahyy");
            String resXML = document.asXML();
            hotelSuccess.info("取消订单响应报文");
            hotelSuccess.info(resXML);
            return resXML;
        } else {
            String resXML = orderCancelFailXml(EchoToken, TimeStamp, errorCode, errorStr);
            return resXML;
        }
    }

    // 返回取消订单失败的xml报文
    public String orderCancelFailXml(String EchoToken, String TimeStamp, int errorCode, String errorStr) {
        Document document = DocumentHelper.createDocument();
        Element otaCancelRS = document.addElement("OTA_CancelRS");
        otaCancelRS.addAttribute("EchoToken", EchoToken);
        otaCancelRS.addAttribute("TimeStamp", TimeStamp);
        otaCancelRS.addAttribute("Version", "1.000");
        otaCancelRS.addAttribute("Status", "Ignored");
        otaCancelRS.addAttribute("PrimaryLangID", "en-us");

        Element Errors = otaCancelRS.addElement("Errors");
        Errors.addElement("Error").addAttribute("Language", "en-us").addAttribute("Type", "3").addAttribute("Code", errorCode + "").setText(errorStr);
        String resXML = document.asXML();
        hotelSuccess.info("取消订单响应报文");
        hotelSuccess.info(resXML);
        return resXML;
    }

    // 返回创建订单成功的xml报文
    public String HotelResRQSuccessXml(String EchoToken, String TimeStamp, String RequestorID, String ElongOrderId, String orderCode) {
        Document document = DocumentHelper.createDocument();
        Element otaInventoryCheckRS = document.addElement("OTA_HotelResRS");
        otaInventoryCheckRS.addAttribute("TimeStamp", TimeStamp);
        otaInventoryCheckRS.addAttribute("Version", "1.000");
        otaInventoryCheckRS.addAttribute("EchoToken", EchoToken);

        Element pos = otaInventoryCheckRS.addElement("POS");
        Element source = pos.addElement("Source");
        Element requestorID = source.addElement("RequestorID");
        requestorID.addAttribute("ID", RequestorID);
        requestorID.addAttribute("Type", "13");

        otaInventoryCheckRS.addElement("Success").setText("success");

        Element UniqueID1 = otaInventoryCheckRS.addElement("UniqueID").addAttribute("ID", ElongOrderId).addAttribute("Type", "14");
        UniqueID1.addElement("CompanyName").setText("elong");

        Element UniqueID2 = otaInventoryCheckRS.addElement("UniqueID").addAttribute("ID", orderCode).addAttribute("Type", "10");
        UniqueID2.addElement("CompanyName").setText("ahyy");
        String resXML = document.asXML();
        hotelSuccess.info("创建订单响应报文");
        hotelSuccess.info(resXML);
        return resXML;
    }


    @Override
    public int insertRemind(String orderCode, int orderType) {
        List<String> allUser = orderMapper.getAllUser();
        return orderMapper.insertRemind(orderCode, allUser, orderType);
    }

    public String getOrderCode() {
        // 获取当前时间
        Date now = new Date();
        // 定义日期格式
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmssSSS");
        // 生成订单号
        String orderNumber = "ahyye" + dateFormat.format(now);
        return orderNumber;
    }

    @Override
    public void yjcl() {
        // 找出所有重复的
        List<Map> quchongfu = orderMapper.quchongfu();
        for (Map map : quchongfu) {
            // 找出所有重复的 houseDayId,除了最早的一条

            // 重复的次数
            int a = Integer.parseInt(map.get("a").toString()) - 1;
            String house_id = map.get("house_id").toString();
            String house_day = map.get("house_day").toString();

            List<String> strings = orderMapper.quchongfuDandu(house_id, house_day);
            System.out.println(strings);
            for (int i = 0; i < a; i++) {
                String id = strings.get(i);
                // 删除el_house_day
                // 删除el_rp_data
                orderMapper.schouse(id);
                orderMapper.scrp(id);
                System.out.println("删除成功" + id);
            }
        }
    }

    @Override
    public void insertPrice() {
        List<Map> order = orderMapper.getOrder();
        for (Map map : order) {
            String RatePlanCode = map.get("rp_id").toString();
            String start = map.get("start_time").toString();
            String end = map.get("end_time").toString();
            String orderCode = map.get("order_code").toString();
            String orderId = map.get("order_id").toString();
            List<Map> rpPriceData = rpMapper.getRpPriceByRpIdAndTime(RatePlanCode, start, end);
            orderMapper.insertOrderPrice(orderId,orderCode, rpPriceData);
        }
    }
}